/*
 * File:   ThreadTable.cpp
 * Author: henrya
 *
 * Created on June 29, 2009, 6:53 AM
 */

#include "ThreadTable.h"
#include "RuntimeException.h"
#include <sstream>
using std::stringstream;
using std::endl;

ThreadTable::ThreadTable(vector<int>* allNodeIds):
allNodeIds(*allNodeIds) {
    status = new ThreadStatus[allNodeIds->size()];
    if ( status== NULL) {
        RuntimeException ex("Could not allocate memory for status");
        throw ex;
    }
    for (unsigned int i=0;i<allNodeIds->size();i++) {
        status[i]=READY;
    }
    accumulatedQuanta = new int[allNodeIds->size()];
    if ( accumulatedQuanta== NULL) {
        RuntimeException ex("Could not allocate memory for accumulatedQuanta");
        throw ex;
    }
    for (unsigned int i=0;i<allNodeIds->size();i++) {
        accumulatedQuanta[i]=0;
    }
    lastQuanta= new int[allNodeIds->size()];
    if ( lastQuanta== NULL) {
        RuntimeException ex("Could not allocate memory for lastQuanta");
        throw ex;
    }
    for (unsigned int i=0;i<allNodeIds->size();i++) {
        lastQuanta[i]=-1;
    }
    usedQuanta= new int[allNodeIds->size()];
    if ( usedQuanta== NULL) {
        RuntimeException ex("Could not allocate memory for usedQuanta");
        throw ex;
    }
    for (unsigned int i=0;i<allNodeIds->size();i++) {
        usedQuanta[i]=-1;
    }
    priority= new int[allNodeIds->size()];
    if ( priority== NULL) {
        RuntimeException ex("Could not allocate memory for priority");
        throw ex;
    }
    for (unsigned int i=0;i<allNodeIds->size();i++) {
        priority[i]=0;
    }
    accUsedQuanta= new int[allNodeIds->size()];
    if ( accUsedQuanta== NULL) {
        RuntimeException ex("Could not allocate memory for accUsedQuanta");
        throw ex;
    }
    for (unsigned int i=0;i<allNodeIds->size();i++) {
        accUsedQuanta[i]=0;
    }
}

ThreadTable::~ThreadTable() {
}

int ThreadTable::getUsedQuanta(int nodeId) {
    return usedQuanta[indexOf(nodeId)];
}

unsigned int ThreadTable::indexOf(int nodeId) {
    for (unsigned int i = 0; i < allNodeIds.size(); i++) {
        if (nodeId == allNodeIds.at(i)) {
            return i;
        }
    }
    return -1;
}

void ThreadTable::updateUsedQuanta(int nodeId, int currQuanta) {
    usedQuanta[indexOf(nodeId)]=lastQuanta[indexOf(nodeId)]-currQuanta;
}

ThreadTable::ThreadStatus ThreadTable::getStatus(int nodeID) {
    return status[indexOf(nodeID)];
}

void ThreadTable::setStatus(int nodeId, ThreadStatus status) {
    this->status[indexOf(nodeId)]=status;
}

int ThreadTable::getAccumulatedQuanta(int nodeId) {
    return accumulatedQuanta[indexOf(nodeId)];
}

void ThreadTable::addQuanta(int nodeId, int quanta) {
    unsigned int index = indexOf(nodeId);
    lastQuanta[index]=quanta;
    accUsedQuanta[index]+=usedQuanta[index];
    usedQuanta[index]=0;
    accumulatedQuanta[index]+=quanta;
}

void ThreadTable::setPriority(int nodeId, int priority) {
    this->priority[indexOf(nodeId)]=priority;
}

int ThreadTable::getPriority(int nodeId) {
    return priority[indexOf(nodeId)];
}

int ThreadTable::getTotalAccumulatedQuanta() {
    int res(0);
    for (unsigned int i = 0; i < allNodeIds.size(); i++) {
        res+=accumulatedQuanta[i];
    }
    return res;
}

string* ThreadTable::getThreadTableString() {
    stringstream res;
    res<<"Node:\tAcc. Quanta:\tAcc. Used Quanta:\tPriority:\tStatus:"<<endl;
    for (unsigned int i = 0; i < allNodeIds.size(); i++) {
        int nodeId=allNodeIds.at(i);
        res<<nodeId<<"\t";
        res<<accumulatedQuanta[i]<<"\t\t\t";
        res<<accUsedQuanta[i]<<"\t\t";
        res<<priority[i]<<"\t\t";
        res<<*getStatusString(status[i])<<endl;
    }
    return new string(res.str());
}

string* ThreadTable::getStatusString(ThreadStatus status) {
    string* res(NULL);
    switch (status) {
    case READY:
        res=new string("READY");
        break;
    case RUNNING:
        res=new string("RUNNING");
        break;
    case BLOCKED:
        res=new string("BLOCKED");
        break;
    }
    return res;
}
